package ort.views.controllers;

import ort.domain.Boxer;
import ort.domain.Experience;
import ort.domain.Fight;
import ort.domain.FightType;
import ort.domain.JudgeCard;
import ort.domain.RoundScore;
import ort.domain.TableJudge;
import ort.persistence.ServerClient;
import ort.utils.NumericUtils;
import ort.utils.WaitJudgeCardThread;

public class GameController {

	private Fight fight = null;
	private TableJudge judge = null;
	private int actualRound = 0;
	private RoundScore actualRoundScore = null;
	public boolean knockOut;
	public boolean throwTowel;

	private static GameController instance = null;

	private GameController() {
	}

	public static GameController getInstance() {
		if (instance == null) {
			instance = new GameController();
		}
		return instance;
	}

	public void init() {

		createFight();
		assignTableJudge();

	}

	public Fight getFight() {
		return fight;
	}

	public void setFight(Fight fight) {
		this.fight = fight;
	}

	public int getActualRound() {
		return actualRound;
	}

	public TableJudge getJudge() {
		return judge;
	}

	public void setJudge(TableJudge judge) {
		this.judge = judge;
	}
	
	public RoundScore getActualRoundScore() {
		return actualRoundScore;
	}

	public void endRound() {

		// Se parametriza el score del juez segun la escala [10,9,9.5]
		this.actualRoundScore.closeRoundScore();

		// Guardo el score del round que se termino
		this.judge.getCard().addRoundScore(this.actualRoundScore);
		
		FormActionController.changeRoundButtonsEnable(false);
		FormActionController.resetRoundPoints();
		
		if (isFightEnd()) {
			FormActionController.changeEndFightLabels();
			JudgeCard judgeCard = GameController.getInstance().endFight();			
			
			// Guardo el juez con su tarjeta
			ServerClient.getInstance().saveJudge(GameController.getInstance().getJudge());
			new WaitJudgeCardThread().run();
			
		}
		this.actualRoundScore = null;
		
	}

	public int startRound() {
		actualRound++;
		this.actualRoundScore = new RoundScore();
		return actualRound;
	}

	// Termina la pelea retornando las tarjetas del Juez asociado a la ejecucion
	// de la aplicacion
	public JudgeCard endFight() {

		this.actualRoundScore = null;
		this.fight = null;

		return judge.getCard();

	}
	
	public boolean isFightEnd(){
		
		// La pelea se termina cuando se terminan los rounds o hubo knock out o se tiro la toalla
		return actualRound == this.fight.getTotalRounds() || knockOut || throwTowel;
	}
	
	
	// Los 2 metodos siguientes tiene las misma logica pero se separaron porque son cosas distintas a nivel de negocio
	public void knockOut(int winnerBoxer){
		this.knockOut = true;
		GameController.getInstance().getJudge().getCard().setWinnerBxerId(winnerBoxer);
	}
	
	public void throwTowel(int  winnerBoxer){
		this.throwTowel = true;
		GameController.getInstance().getJudge().getCard().setWinnerBxerId(winnerBoxer);
	}

	private void createFight() {

		ServerClient serverClient = ServerClient.getInstance();

		// Seteo la pelea en caso de no estar setada
		Fight fight = serverClient.getFigth(); 
		if (fight == null) {

			fight = createRandomFight();
			serverClient.saveFight(fight);
			
		}
		GameController.getInstance().setFight(fight);
	}

	private void assignTableJudge() {

		ServerClient serverClient = ServerClient.getInstance();

		int judgeId = serverClient.getNextJudgeId();
		System.out.println(judgeId);
		TableJudge tableJudge = new TableJudge(judgeId);

		// Guardo el juez en el servidor compartido
		serverClient.saveJudge(tableJudge);

		// Guardo el juez en el controlador de juego de la aplicacion
		GameController.getInstance().setJudge(tableJudge);

	}

	public static void main(String[] args) {
		GameController app = new GameController();
		app.init();

		ServerClient serverClient = ServerClient.getInstance();
		Fight fight = serverClient.getFigth();
		System.out.println(fight);

		for (int i = 1; i <= 3; i++) {
			TableJudge judge = serverClient.getJudge(i);
			if (judge != null) {
				System.out.println(judge);
			}
		}

	}

	private Fight createRandomFight() {

		Boxer boxer1 = new Boxer("Boxeador 1",
				Experience.DIEZ_ROUNDS);
		Boxer boxer2 = new Boxer("Boxeador 2",
				Experience.DIEZ_ROUNDS);

		int fightTypeId = NumericUtils.aleatorio(3);
		FightType type = FightType.AMATEUR;
		if (fightTypeId == 1) {
			type = FightType.PROFESSIONAL;
		} else if (fightTypeId == 2){
			type = FightType.CHAMPIONSHIP;
		}
		
		return new Fight(type, boxer1, boxer2);
	}

}
